/**
 * 列表 hook
 * @author luguoxiang
 * @date 2024-06-19
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
import {onLoad, onPullDownRefresh, onReachBottom} from "@dcloudio/uni-app";
// @ts-ignore
import {reactive, provide, ref, watch} from "vue"
import type {Api} from "../types/Types";
import {toPromise} from "../utils/data"
import message from "../utils/message"
import {back as refreshBack} from '@/soar/hooks/refresh';

export const FORM_PROPS = {
	class: 'gl-form',
	labelWidth: '6em',
}

function copy(data: any) {
	if (data === undefined || data === null || typeof data !== 'object') {
		return data
	}
	return JSON.parse(JSON.stringify(data))
}

/**
 * 使用list
 * @param {UseListOptions} options
 * @return
 */
export function useList<T>(options: UseListOptions) {
	const {
		api,
		immediate = true,
		params: initParams = {},
		useReachBottom = true,
		pageSize = 15,
		orderBy = [],
	} = options;
	// @ts-ignore
	const query = typeof api === 'function' ? api : api.query;
	const data = ref<T[]>([]); // 数据
	const pageNo = ref(1); // 页码
	const hasMore = ref(true); // 是否有更多数据
	const loading = ref(false); // 是否加载中
	const total = ref(0); // 总记录数
	const params = ref(copy(initParams)); // 搜索参数

	/**
	 * 加载更多数据(加载下一页数据)
	 * @return
	 */
	function loadMore(): Promise<any> {
		if (!hasMore.value) {
			return Promise.reject(new Error('没有更多数据'))
		}
		const queryParams = {
			...params.value,
			pageNo: pageNo.value,
			pageSize,
			orderBy,
		}
		loading.value = true;
		// @ts-ignore
		return toPromise(query(queryParams)).then(res => {
			if ('data' in res) {
				res = res.data;
			}
			if (Array.isArray(res)) {
				res = { list: res, total: res.length }
			}
			data.value = data.value.concat(res.list);
			total.value = res.total;
			hasMore.value = res.total > data.value.length;
			pageNo.value++;
			return res
		}).catch(err => {
			message.error(err.response?.msg || '请求失败')
		}).finally(() => loading.value = false)
	}

	/**
	 * 触发查询（回到第一页）
	 * @return
	 */
	function onQuery(): Promise<any> {
		pageNo.value = 1;
		data.value = [];
		hasMore.value = true;
		return loadMore();
	}

	/**
	 * 重置查询（还原搜索参数在触发查询）
	 * @return
	 */
	function onResetQuery(): Promise<any> {
		pageNo.value = 1;
		params.value = copy(initParams);
		return onQuery();
	}

	// 立即加载数据
	if (immediate) {
		onLoad(onQuery)
	}

	// 使用页面上拉下拉加载数据
	if (useReachBottom) {
		onPullDownRefresh(() => {
			onQuery().then(() => uni.stopPullDownRefresh())
		})
		onReachBottom(loadMore)
	}

	return {
		params,
		data,
		total,
		hasMore,
		loading,
		loadMore,
		onQuery,
		onResetQuery,
	}
}


export function useForm<T>(options: UseFormOptions<T>) {
	const {
		api = {},
		immediate = true,
		model: initModel = {},
		interceptBackButton = false,
		formRef: fref,
		showLoading = true,
	} = options;
	const formRef = fref ?? ref();
	const detail = typeof api === 'function' ? api : api.detail;
	const model = ref(copy(initModel));
	const formProps = reactive({
		...FORM_PROPS,
		...(fref ? null : {
			ref(e: any) {
				formRef.value = e;
			}
		})
	});
	const mode = reactive<{
		create: boolean;
		update: boolean;
		detail: boolean;
		name: string;
		value: string;
	}>({
		create: false,
		update: false,
		detail: false,
		name: '',
		value: '',
	});
	const loading = ref(false); // 是否加载中

	if (showLoading) {
		watch(
			() => loading.value,
			(v) => {
				if (v) {
					uni.showLoading()
				} else {
					uni.hideLoading()
				}
			},
			{ immediate: true }
		)
	}

	onLoad((query: any) => {
		mode.value = query._mode;

		for (const key in query) {
			if (key.startsWith('_')) {
				continue
			}
			// @ts-ignore
			model.value[key] = query[key];
		}
		// 立即加载数据
		if (detail && immediate && query.id) {
			toPromise(detail(query.id)).then(res => {
				if ('data' in res) {
					res = res.data
				}
				if (mode.value === 'copy') {
					delete res.id;
				}
				model.value = res
			}).catch(err => {
				message.error(err.msg)
			}).finally(() => {
				loading.value = false;
			})
			loading.value = true;
		}

		// 模式
		if (mode.value === 'detail') {
			mode.detail = true;
			mode.create = false;
			mode.update = false;
			mode.name = '详情';
		} else if (mode.value === 'copy') {
			mode.detail = false;
			mode.create = true;
			mode.update = false;
			mode.name = '复制';
		} else if (query.id) {
			mode.detail = false;
			mode.create = false;
			mode.update = true;
			mode.name = '修改';
		} else {
			mode.detail = false;
			mode.create = true;
			mode.update = false;
			mode.name = '新增';
		}
	})

	/**
	 * 返回
	 * @param {any} warn
	 * @param {any} refresh
	 * @return
	 */
	function back(warn = true, refresh = false) {
		message.confirm({
			title: '警告',
			message: '表单未提交，确定返回吗？',
			enabled: warn
		}).then(() => {
			refreshBack({ refresh })
		})
	}

	/**
	 * 提交后置处理
	 * @param {Promise<any>} promise
	 * @return
	 */
	function onSubmitAfter(promise: Promise<any>) {
		loading.value = true;
		promise
			.then(() => {
				message.success('操作成功')
				back(false, true);
			})
			.catch(err => {
				message.error(err.msg)
			})
			.finally(() => loading.value = false)
	}

	/**
	 * 校验表单，通过返回表单数据
	 */
	function validate(): Promise<T> {
		return formRef.value.validate().then(()=>{
			return model.value as T;
		}).catch((err: string | any[]) => {
			console.warn(err);
			if (Array.isArray(err) && err.length) {
				message.error(err[0].errorMessage)
			}
		})
	}

	/**
	 * 清除校验
	 */
	function clearValidate(): Promise<T> {
		return formRef.value.clearValidate()
	}

	/**
	 * 重置表单
	 */
	function resetFields() {
		// @ts-ignore
		model.value = copy(initModel);
		formRef.value.resetFields();
	}

	const { execute: executeAsyncComponent } = useAsyncComponent();

	/**
	 * 提交
	 * @return
	 */
	function onSubmit() {
		validate().then((value)=>{
			executeAsyncComponent().then(() => {
				if (mode.create || mode.value === 'copy') {
					onSubmitAfter(
						// @ts-ignore
						toPromise(api.create(value))
					)
				} else if (mode.update) {
					onSubmitAfter(
						// @ts-ignore
						toPromise(api.update(value))
					)
				}
			})
		});
	}

	// 自动拦截返回
	if (interceptBackButton) {
		uni.addInterceptor('navigateBack', {
			invoke(args) {
				if (!mode.detail && args.from === "backbutton") {
					back()
					return false
				}
			},
		})
	}

	// onUnload(() => {
	// 	resetFields();
	// })

	return {
		model,
		mode,
		loading,
		onSubmit,
		onSubmitAfter,
		back,
		validate,
		clearValidate,
		resetFields,
		executeAsyncComponent,
		formProps,
		formRef,
	}
}

/**
 * 需要附件上传的表单使用，提交时调用 upload 方法等待所有附件上传完成才能提交表单
 */
function useAsyncComponent() {
	const set: Set<any> = new Set()
	provide('async-component:register', (i: any) => {
		set.add(i)
	})
	provide('async-component:deregister', (i: any) => {
		set.delete(i)
	})

	/**
	 * 执行异步组件
	 */
	function execute() {
		const promises = [];
		for (const x of set) {
			promises.push(x())
		}
		return Promise.all(promises)
	}

	return { execute }
}

/**
 * useList 配置项
 */
export interface UseListOptions {

	/**
	 * 接口
	 */
	api: Api | Api['query'];

	/**
	 * 是否立即加载数据，默认：true
	 */
	immediate?: boolean;

	/**
	 * 默认参数
	 */
	params?: { [k: string]: any };

	/**
	 * 是否使用页面上拉加载更多，默认：true
	 */
	useReachBottom?: boolean;

	/**
	 * 分页大小配置，默认：15
	 */
	pageSize?: number;
	
	/**
	 * 排序方式
	 */
	orderBy?: string[],
}

/**
 * useForm 配置项
 */
export interface UseFormOptions<T> {
	/**
	 * 接口
	 */
	api?: Api | Api['detail'];

	/**
	 * 是否立即加载数据，默认：true
	 */
	immediate?: boolean;

	/**
	 * 默认数据
	 */
	model?: T | { [k: string]: any };

	/**
	 * 是否拦截返回按钮
	 */
	interceptBackButton?: boolean;

	/**
	 * 表单引用
	 */
	formRef?: any;

	/**
	 * 是否显示加载中提示
	 */
	showLoading?: boolean;
}